package org.jprobe.codegen;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * Implementation of UnimplementedMethodExplorerInterface
 *
 * @author Hussain Al-Mutawa
 * @version 1.0
 * @since 1.0
 */
public class UnimplementedMethodsExplorer implements UnimplementedMethodsExplorerInterface {
	/** collection of abstract methods **/
	private transient final Map<String,Method>ABSTRACT_METHODS;

	/**
	 * initializes the explorer and prepares the collection of methods
	 * @param declaredBy a sub-class inheriting abstract super class(es)
	 **/
	public UnimplementedMethodsExplorer(final Class<?>what) {
		super();

		 this.ABSTRACT_METHODS = new TreeMap<String,Method>();
         Class<?>aclazz=what;
         Set<Method>methods;
         do{
                 methods=getClassMethods(aclazz);
                 for(final Method method:methods){
                         if(Modifier.isAbstract(method.getModifiers())){
                                 final String name = getShortMethodName(method);
                                 this.ABSTRACT_METHODS.put(name, method);
                         }
                 }
                 aclazz=aclazz.getSuperclass();
         }while(!(aclazz==null || aclazz==Object.class));

	}

	private Set<Method> getClassMethods(final Class<?> aclazz) {
		final Set<Method>methods=new HashSet<Method>(Arrays.asList(aclazz.getDeclaredMethods()));
		methods.addAll(Arrays.asList(aclazz.getMethods()));
		return methods;
	}

	@Override
	public Method[]getAbstractMethods(){
		final Method[]result=this.ABSTRACT_METHODS.values().toArray(new Method[this.ABSTRACT_METHODS.size()]);
		return result;
	}

	@Override
	public String[]getAbstractMethodsNames(){
		final String[]result=this.ABSTRACT_METHODS.keySet().toArray(new String[this.ABSTRACT_METHODS.size()]);
		return result;
	}

	/**
	 * gets a method shorten name, by removing the declaring class name from the method name.
	 * @param method a method declared by class
	 * @return
	 */
	public static String getShortMethodName(final Method method){
		return method.toString().replace(method.getDeclaringClass().getName()+'.', "");
	}
}
